import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';

import 'package:flutter/cupertino.dart';
import 'package:my_salary/core/auth/token_provider.dart';
import 'package:my_salary/core/auth/user_profile.dart';
import 'package:pointycastle/api.dart';
import 'package:pointycastle/block/aes.dart';
import 'package:pointycastle/block/modes/gcm.dart';

import '../../api/api_auth_center.dart';
import '../capabilities/biometric_service.dart';
import '../secure/flutter_secure_store.dart';
import '../secure/secure_store.dart';
import 'user_session.dart';
import 'dart:math';

class UserManager extends ChangeNotifier implements TokenProvider {
  // 单例
  static final UserManager _instance = UserManager._internal();

  factory UserManager() => _instance;

  UserManager._internal();

  // 安全存储
  final SecureStore _sec = FlutterSecureKV();

  // 存储键
  static const _profileKey = 'current_user_profile';
  static const _sessionKey = 'current_user_session';
  static const _enableBiometricLockKey = 'enableBiometricLock';

  // 生物识别
  final biometricService = BiometricService();

  // 提前多少时间刷新 Token
  Duration refreshSkew = const Duration(minutes: 2); // 提前刷新窗口

  UserSession? _session;
  UserProfile? _profile;
  DateTime? _tokenExpiry;
  Future<void>? _refreshing; // 刷新中的合并 Future

  UserProfile? get profile => _profile;

  UserSession? get session => _session;

  bool get isLoggedIn => _session != null && _tokenExpiry != null;

  /// 启用或禁用生物识别登录
  Future<void> setBiometricLockEnabled(bool enabled) async {
    if (enabled) {
      final available = await biometricService.isAvailable();
      if (!available) {
        throw Exception('Biometric authentication is not available');
      }
    }
    await _sec.write(_enableBiometricLockKey, enabled ? 'true' : 'false');
  }

  Future<bool> isBiometricLockEnabled() async {
    return await _sec.read(_enableBiometricLockKey) == 'true';
  }

  // 启动时加载 + 校验
  Future<void> loadAndValidateOnLaunch() async {
    final pStr = await _sec.read(_profileKey);
    final sStr = await _sec.read(_sessionKey);

    if (pStr == null || sStr == null) {
      await clearAll();
      return;
    }

    try {
      _profile = UserProfile.fromJson(jsonDecode(pStr));
      _session = UserSession.fromJson(jsonDecode(sStr));
      _tokenExpiry = _session?.expireAt;
    } catch (_) {
      await clearAll();
      return;
    }

    // 强制刷新一次（确保启动时 token 是最新的）
    await refreshTokenIfNeeded(force: true);

    // 校验新 token 是否有效
    final ok = await _validateTokenWithServer();
    if (!ok) {
      await clearAll();
    } else {
      notifyListeners();
    }
  }

  // 登录成功后保存（资料和 token 分开保存）
  Future<void> saveSession(UserSession session) async {
    _session = session;
    _tokenExpiry = session.expireAt;
    await _sec.write(_sessionKey, jsonEncode(session.toJson()));
    notifyListeners();
  }

  // 更新用户资料（不涉及 token）
  Future<void> updateProfile(UserProfile profile) async {
    _profile = profile;
    await _sec.write(_profileKey, jsonEncode(profile.toJson()));
    notifyListeners();
  }

  // 清除所有（登出）
  Future<void> clearAll() async {
    _profile = null;
    _session = null;
    _tokenExpiry = null;
    await _sec.delete(_profileKey);
    await _sec.delete(_sessionKey);
    notifyListeners();
  }

  // 判断是否需要刷新
  bool _needRefresh() {
    final exp = _tokenExpiry;
    if (exp == null) return false;
    final now = DateTime.now();
    return now.isAfter(exp.subtract(refreshSkew));
  }

  // 读取 AccessToken（必要时自动刷新）
  @override
  Future<String?> getValidAccessToken() async {
    if (!isLoggedIn) return null;
    await refreshTokenIfNeeded();
    return _session!.accessToken;
  }

  // 并发去抖的自动刷新（必要时）
  @override
  Future<void> refreshTokenIfNeeded({bool force = false}) async {
    if (!isLoggedIn) return;
    if (!force && !_needRefresh()) return;

    if (_refreshing != null) {
      // 已有刷新在进行，等待同一个 Future
      await _refreshing;
      return;
    }

    final completer = Completer<void>();
    _refreshing = completer.future;

    try {
      final success = await refreshToken();
      if (!success) {
        await clearAll(); // 刷新失败，安全登出
      }
      completer.complete();
    } catch (e) {
      completer.completeError(e);
      rethrow;
    } finally {
      _refreshing = null;
    }
  }

  // 实际调用后端刷新接口
  @override
  Future<bool> refreshToken() async {
    if (!isLoggedIn || _session?.refreshToken == null) return false;

    try {
      final rft = _session!.refreshToken;
      final authTokenResponse = await ApiAuthCenter.api.refreshToken(rft);

      final newSession = UserSession(
        gsid: authTokenResponse!.gsid,
        accessToken: authTokenResponse.accessToken,
        refreshToken: authTokenResponse.refreshToken,
        expireAt:
            DateTime.now().add(Duration(seconds: authTokenResponse.expiresIn)),
      );

      await saveSession(newSession);
      return true;
    } catch (e) {
      return false;
    }
  }

  // 启动时的轻量校验：调用 /api/auth/me 确认 token 有效
  Future<bool> _validateTokenWithServer() async {
    try {
      final authMeResponse = await ApiAuthCenter.api.me();

      final newProfile = UserProfile(
        id: authMeResponse!.userId,
        username: authMeResponse.username,
        nickname: authMeResponse.nickname,
        phone: authMeResponse.phone,
        email: authMeResponse.email,
        avatar: authMeResponse.avatar,
      );

      await updateProfile(newProfile);
      return true;
    } catch (e) {
      return false;
    }
  }
}

class RememberMeStorage {
  static final RememberMeStorage _instance = RememberMeStorage._internal();

  factory RememberMeStorage() => _instance;

  RememberMeStorage._internal();

  static final _secure = FlutterSecureKV();
  static final _rand = Random.secure();

  static const _dataKey = 'remember_me_data_v2';
  static const _flagKey = 'remember_me_flag_v2';
  static const _aesKeyName = 'remember_me_aes_key_v2';

  Uint8List _b64d(String s) => base64Url.decode(s);

  String _b64e(Uint8List bytes) => base64Url.encode(bytes);

  Uint8List randomBytes(int length) {
    final out = Uint8List(length);
    for (var i = 0; i < length; i++) {
      out[i] = _rand.nextInt(256);
    }
    return out;
  }

  Future<Uint8List> _getOrCreateKey() async {
    final existing = await _secure.read(_aesKeyName);
    if (existing != null) return _b64d(existing);

    final keyBytes = randomBytes(32); // 256-bit
    await _secure.write(_aesKeyName, _b64e(keyBytes));
    return keyBytes;
  }

  Uint8List _encrypt(Uint8List key, Uint8List nonce, Uint8List plainText) {
    final cipher = GCMBlockCipher(AESEngine())
      ..init(true, AEADParameters(KeyParameter(key), 128, nonce, Uint8List(0)));
    return cipher.process(plainText);
  }

  Uint8List _decrypt(Uint8List key, Uint8List nonce, Uint8List cipherText) {
    final cipher = GCMBlockCipher(AESEngine())
      ..init(
          false, AEADParameters(KeyParameter(key), 128, nonce, Uint8List(0)));
    return cipher.process(cipherText);
  }

  Future<void> save(RememberMe data) async {
    final key = await _getOrCreateKey();
    final nonce = randomBytes(12);
    final plain = utf8.encode(jsonEncode(data.toJson()));
    final cipher = _encrypt(key, nonce, Uint8List.fromList(plain));

    final payload = jsonEncode({
      'v': 1,
      'n': _b64e(nonce),
      'c': _b64e(cipher),
    });

    await _secure.write(_dataKey, payload);
    await _secure.write(_flagKey, 'true');
  }

  Future<RememberMe?> load() async {
    final remember = await _secure.read(_flagKey) ?? 'false';
    if (remember != 'true') return null;

    final payload = await _secure.read(_dataKey);
    if (payload == null) return null;

    try {
      final map = jsonDecode(payload) as Map<String, dynamic>;
      final version = (map['v'] as num?)?.toInt() ?? 1;
      final nStr = map['n'] as String?;
      final cStr = map['c'] as String?;
      if (nStr == null || cStr == null) {
        throw const FormatException('Malformed payload');
      }

      final nonce = _b64d(nStr);
      final cipher = _b64d(cStr);
      if (nonce.length != 12) {
        throw const FormatException('Invalid nonce length');
      }

      final key = await _getOrCreateKey();
      final clear = _decrypt(key, nonce, cipher);
      final obj = jsonDecode(utf8.decode(clear)) as Map<String, dynamic>;
      return RememberMe.fromJson(obj);
    } catch (e) {
      await clear();
      return null;
    }
  }

  Future<void> clear() async {
    await _secure.delete(_dataKey);
    await _secure.write(_flagKey, 'false');
  }
}
